home *** CD-ROM | disk | FTP | other *** search
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ;
- ; Sound support - GUS & SB
- ;
- ; Labels begining with:
- ; _sfx - generic sound commands, both cards
- ; _gs - GUS labels
- ; _sb - Sound Blaster labels
- ;
- ; Notes and Examples:
- ;
- ; call _sfx_find ; for both soundcards
- ; jc no sound card installed
- ;
- ; mov edx,_lomembase ; DMA buffer * ALL this data is ignored *
- ; mov ebx, 1024 ; DMA buffer size * if the user has a GUS *
- ; mov ecx, 22000 ; sample rate
- ; mov eax,_lomembase
- ; add eax, ebx ; samples are right after DMA buffer
- ; call _sfx_init ; call this for both soundcards (SB and GUS)
- ; mul ebx,200000 ; 200000 bytes of sample memory required (0 if GUS)
- ; add _lomembase,eax ; bump up low memory because of DMA (0 if GUS)
- ; add _lomembase,ebx ; bump up low memory because of samples required (0 if GUS)
- ;
- ; call _sfx_uninit ; done, clear soundcard
- ;
- ; Notes: Original GUS code (now modified) from GS.ASM by Thomas Pytel, aka TRAN
- ; Sound Blaster code (Gravis Emulation) by John McCarthy, aka FLYNN.
- ;
- ; Send me a postcard!
- ;
- ; John McCarthy
- ; 1316 Redwood Lane
- ; Pickering, Ontario.
- ; Canada, Earth, Milky Way (for those out-of-towners)
- ; L1X 1C5
- ;
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- .386p
- code32 segment para public use32
- assume cs:code32, ds:code32
-
- include pmode.ext
- include irq.ext
- include file.ext
-
- public _sfx_find ; find if sound device available
- public _sfx_init ; intialize sound device
- public _sfx_uninit ; unintialize sound device
- public _sfx_putram ; put to ram
- public _sfx_getram ; get from ram
- public _sfx_shutup ; turn single voice off
- public _sfx_relvolume ; relative volume control
- public _sfx_setvolume ; set volume of channel
- public _sfx_getfreq
-
- public _freqtbl ; precalculated frequencies for c0 to b4
-
- public _sfxnumvoices ; number of voices to mix
- public _sfxmem ; next available location in sample memory
- public _sfxram ; amount of RAM on card
- public _sfxsign ; sign for XOR'ing of samples (only during
- ; initial transfer to card)
- public _sfxtype ; card installed, 0 = none, 1 = GUS, 2 = SB
-
- public _vccmnd, _vccntrl, _vcsbeg, _vclbeg, _vclend, _vcfreq, _vcpan, _vcvol
- public _mix_volume
-
- align 4
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Generic voice handling stuff
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sfx_init dd offset _return_null ; jump vectors to appropriate code
- _sfx_uninit dd offset _return_null
- _sfx_putram dd offset _return_null
- _sfx_getram dd offset _return_null
- _sfx_shutup dd offset _return_null
- _sfx_getfreq dd offset _return_null
-
- _sfxsign db 0 ; signed data not, 0 = SB, 80h = GUS
- _sfxmem dd 0 ; next free location in GUS or SB virtual memory
- _sfxram dd 0 ; amount of available GUS or SB virtual memory
- _sfxnumvoices db 16 ; number of voices (up to 32)
- _sfxmiddlec dw 8664 ; Hz assigned to middle C
- _sfxtype db 0 ; card installed, 0 = none, 1 = GUS, 2 = SB
- ; bit 1, 1 = virtual ram or 0 = GUS ram/no ram
-
- _vccmnd db 32 dup(?) ; virtual channel command bits
- ; bit 0: volume change
- ; bit 1: balance change
- ; bit 2: frequency change
- ; bit 3: sample note-on
- ; bit 4: sample continues into next chunk (SB only)
- _vccntrl db 32 dup(?) ; virtual channel voice control
- ; bit 3: enable loop
- ; bit 4: bi-directional loop
- ; bit 6: 0=forward, 1=reverse
- _vcsbeg dd 32 dup(?) ; virtual channel sample begin
- _vclbeg dd 32 dup(?) ; virtual channel loop begin
- _vclend dd 32 dup(?) ; virtual channel loop end
- _vcfreq dw 32 dup(?) ; virtual channel frequency value
- _vcpan db 32 dup(?) ; virtual channel pan position
- _vcvol db 32 dup(?) ; virtual channel volume (high byte)
-
- _mix_volume db 32 dup(15) ; mixing volume (each channel)
-
- aclbeg dd 32 dup(?) ; actual channel loop begin
- aclend dd 32 dup(?) ; actual channel loop end
- acfreq dw 32 dup(?) ; actual channel frequency value
- acpan db 32 dup(?) ; actual channel pan position
- acvol db 32 dup(?) ; actual channel volume (high byte)
- acpos dd 32 dup(?) ; actual channel position (SB only)
- acstep db 32 dup(?) ; actual channel last step position (SB only)
- accntrl db 32 dup(?) ; actual channel voice control (SB only)
- accmnd db 32 dup(?) ; actual channel command (SB only)
-
- _freqtbl dw 60 dup (0)
-
- rawfreq dw 2166,2294,2431,2573,2728,2891,3063,3245,3438,3642,3859,4088
- dw 4332,4589,4862,5147,5457,5782,6126,6490,6876,7285,7718,8177
- dw 8664,9179,9725,10294,10915,11565,12252,12981,13752,14571,15437,16355
- dw 17328,18358,19450,20589,21831,23130,24505,25962,27505,29142,30874,32710
- dw 34656,36716,38900,41179,43663,46260,49011,51925,55010,58284,61749,65421
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Null soundcard (default)
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _return_null:
- xor eax,eax
- xor ebx,ebx
- xor ecx,ecx
- xor edx,edx
- xor esi,esi
- xor edi,edi
- xor ebp,ebp
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Macros
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- vol = 1 ; alter volume
- pan = 2 ; alter pan position
- freq = 4 ; alter frequency
- play = 8 ; start/re-start sample
- cont = 16 ; continue with SB sample (for next chunk, SB only)
- shutup = 32 ; turn channel completly off
-
- loop_on = 8 ; looping enable
- loop_bi = 16 ; bi-directional loop
- loop_rev = 64 ; loop direction, 1 = backwards
-
- gusoutb macro index,value
- mov al,&index
- out dx,al
- add dl,2
- mov al,&value
- out dx,al
- sub dl,2
- endm
-
- gusoutw macro index,value
- mov al,&index
- out dx,al
- inc edx
- mov ax,&value
- out dx,ax
- dec edx
- endm
-
- gusinb macro reg,index
- mov al,&index
- out dx,al
- add dl,2
- in al,dx
- sub dl,2
- ifnb <reg>
- mov reg,al
- endif
- endm
-
- gusinw macro reg,index
- mov al,&index
- out dx,al
- inc edx
- in ax,dx
- dec edx
- ifnb <reg>
- mov reg,ax
- endif
- endm
-
- sbout macro data
- local wait
- wait: in al,dx
- or al,al
- js wait
- mov al,data
- out dx,al
- endm
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Perform Initial test for card: Set jump vectors for card found
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sfx_find:
- mov _sfxtype,0
-
- call _gus_find
- jc fd_looksb
-
- mov _sfx_init ,offset _gus_init
- mov _sfx_uninit,offset _gus_uninit
- mov _sfx_putram,offset _gus_putram
- mov _sfx_getram,offset _gus_getram
- mov _sfx_shutup,offset _gus_shutup
- mov _sfx_getfreq,offset _gus_getfreq
- mov _sfxtype,1
- mov _sfxsign,0
- ret
-
- fd_looksb:
- call _sb_find
- jc _ret
- mov _sfx_init ,offset _sb_init
- mov _sfx_uninit,offset _sb_uninit
- mov _sfx_putram,offset _sb_putram
- mov _sfx_getram,offset _sb_getram
- mov _sfx_shutup,offset _sb_shutup
- mov _sfx_getfreq,offset _sb_getfreq
- mov _sfxtype,2
- mov _sfxsign,0
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Set mixing volume of channel EBX
- ; In:
- ; EBX - voice channel #
- ; AL - volume level
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sfx_setvolume:
- cmp al,0
- jge sv_1
- mov al,0
- sv_1:
- cmp al,15
- jle sv_2
- mov al,15
- sv_2:
- mov _mix_volume[ebx],al
- or _vccmnd[ebx],vol
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Change volume of channels (relative)
- ; In:
- ; BL - channel to start at
- ; CL - channel to end at
- ; DL - 1 = inc, -1 = dec
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sfx_relvolume:
- sub cl,bl
- inc cl
- movzx ebx,bl
- movzx ecx,cl
- av_1:
- mov al,_mix_volume[ebx]
- add al,dl
- call _sfx_setvolume
- inc ebx
- loop av_1
-
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; GUS lowlevel interface. Part II - modified from TRAN's original gs.asm
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- public _gus_handler
- public _gus_shutup
- public _gus_init
- public _gus_uninit
- public _gus_putram
- public _gus_getram
- public _gus_find
- public _gus_getfreq
-
- public _gusport
- public _gusirq
-
- ormgusirqvect dd ? ; old real mode GF1 IRQ vector
- rmgusirqbuf db 21 dup(?) ; buffer for rm GF1 IRQ callback code
-
- gusport102 dw ? ; GUS port + 102h
- gusport103 dw ? ; GUS port + 103h
- gusport104 dw ? ; GUS port + 104h
- gusport107 dw ? ; GUS port + 107h
-
- _gusport dw 220h
- _gusirq db 11
-
- whichguscontrol dd -1 ; irq timing control number
-
- port103val db 43h ; value to set on exit from IRQ
- irqm0tbl dw 0c089h,0a0e6h
- gusirqvaltbl db 0,0,41h,43h,0,42h,0,44h,0,0,0,45h,46h,0,0,47h
-
- voltbl db 004h,0a0h,0b0h,0c0h,0c8h,0d0h,0d8h,0e0h
- db 0e4h,0e8h,0ech,0f0h,0f2h,0f4h,0f6h,0f8h
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Gus IRQ - useless, never called
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- gus_irq:
- push eax
- mov al,20h
- out 20h,al
- irqm0 dw ? ; out 0a0h,al | mov eax,eax
- sti
- cld
- push ebx ecx edx esi edi ebp ds
- mov ds, [cs:_seldata]
-
-
-
- pop ds ebp edi esi edx ecx ebx eax
- iretd
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Gus voice handler
- ; Update GUS from virtual values/commands
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _gus_handler:
- mov dx,gusport103
- movzx ebp,_sfxnumvoices
- dec ebp
- irql0:
- xor cl,cl
- xchg cl,_vccmnd[ebp]
- or cl,cl
- jz irql0c
-
- test cl,shutup
- jz short irql0f9
- mov edi,ebp
- call _gus_shutup
- jmp irql0c
- irql0f9:
- test cl,play
- jz short irql0f0
- or cl,vol+pan+freq
- irql0f0:
-
- mov eax,ebp
- dec edx
- out dx,al
- inc edx
-
- cmp _mix_volume[ebp],0
- jne irql0g1
- gusoutb 0,1
- jmp irql0c
-
- irql0g1:
- test cl,freq
- jz short irql0f1
- mov bx,_vcfreq[ebp*2]
- cmp bx,acfreq[ebp*2]
- je short irql0f1
- mov acfreq[ebp*2],bx
- gusoutw 1,bx
- irql0f1:
-
- test cl,pan
- jz short irql0f2
- mov bl,_vcpan[ebp]
- cmp bl,acpan[ebp]
- je short irql0f2
- mov acpan[ebp],bl
- gusoutb 0ch,bl
- irql0f2:
-
- test cl,play
- jz irql0f3
- mov esi,_vclbeg[ebp*4]
- cmp esi,aclbeg[ebp*4]
- je short irql0f2f0
- mov aclbeg[ebp*4],esi
- shrd bx,si,7
- shr esi,7
- gusoutw 2,si
- gusoutb 3,bh
- irql0f2f0:
- mov esi,_vclend[ebp*4]
- cmp esi,aclend[ebp*4]
- je short irql0f2f1
- mov aclend[ebp*4],esi
- shrd bx,si,7
- shr esi,7
- gusoutw 4,si
- gusoutb 5,bh
- irql0f2f1:
- mov esi,_vcsbeg[ebp*4]
- shrd bx,si,7
- shr esi,7
- gusoutw 0ah,si
- gusoutb 0bh,bh
- gusoutb 0,_vccntrl[ebp]
- irql0f3:
-
- test cl,vol
- jz short irql0f4
- movzx ebx,_vcvol[ebp]
- mov bl,voltbl[ebx]
- cmp bl,4
- jbe irql0f3f4
- mov bh,_mix_volume[ebp]
- shl bh,3
- sub bh,_mix_volume[ebp] ; *7
- add bl,bh
- sub bl,105 ; 7*15
- irql0f3f4:
- mov bh,acvol[ebp]
- mov ah,bh
- cmp bh,bl
- je short irql0f4
- mov ch,40h
- ja short irql0f3f0
- xchg bl,bh
- xor ch,ch
- irql0f3f0:
- gusoutb 7,bl
- gusoutb 8,bh
- gusoutb 9,ah
- gusoutb 0dh,ch
- irql0f4:
-
- mov dx,300h
- db 7 dup(0ech) ; in al,dx
- mov dx,gusport103
-
- test cl,vol
- jz short irql0f5
- movzx ebx,_vcvol[ebp]
- mov al,voltbl[ebx]
- cmp al,4
- jbe irql0f5f4
- mov bh,_mix_volume[ebp]
- shl bh,3
- sub bh,_mix_volume[ebp] ; *7
- add al,bh
- sub al,105 ; 7*15
- irql0f5f4:
- cmp al,ah
- je short irql0f5
- mov acvol[ebp],al
- gusoutb 9,ah
- gusoutb 0dh,ch
- irql0f5:
-
- test cl,play
- jz short irql0c
- mov esi,_vcsbeg[ebp*4]
- shrd bx,si,7
- shr esi,7
- gusoutw 0ah,si
- gusoutb 0bh,bh
- gusoutb 0,_vccntrl[ebp]
-
- irql0c:
- sub ebp,1
- jnc irql0
-
- outb port103val
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; A small delay, In: ECX - number of times to do delay
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- gusdelay:
- push ax dx
- mov dx,300h
- gusdelayl0:
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- loop gusdelayl0
- pop dx ax
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Shove some crap into GUS ram
- ; In:
- ; EBX - addx in GUS ram to shove into
- ; ECX - amount of crap to shove
- ; EDX -> actual crap to shove
- ; Notes:
- ; All incoming data will be XOR'ed with _sfxsign !!!
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- _gus_putram:
- push eax ebx ecx edx esi
- push ecx
- mov al,_sfxsign
- xor al,80h
- gsputramlx:
- xor byte ptr [edx],al
- inc edx
- loop gsputramlx
- pop ecx
- sub edx,ecx
- mov esi,edx
- mov dx,gusport104
- gsputraml0:
- dec edx
- mov al,44h
- mov port103val,al
- out dx,al
- add dl,2
- shld eax,ebx,16
- out dx,al
- sub dl,2
- mov al,43h
- mov port103val,al
- out dx,al
- inc edx
- gsputraml1:
- mov ax,bx
- out dx,ax
- add dl,3
- outsb
- sub dl,3
- inc bx
- loopnz gsputraml1
- jecxz short gsputramd
- add ebx,10000h
- jmp gsputraml0
- gsputramd:
- pop esi edx ecx ebx eax
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Rip some crap outta GUS ram
- ; In:
- ; EBX - addx in GUS ram to rip from
- ; ECX - amount of crap to rip
- ; EDX -> buffer for ripped crap
- ; Notes:
- ; All outgoing data will be XOR'ed with _sfxsign !!!
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- _gus_getram:
- push eax ebx ecx dx edi
- push ecx
- mov al,_sfxsign
- xor al,80h
- gsgetramlx:
- xor byte ptr [edx],al
- inc edx
- loop gsgetramlx
- pop ecx
- sub edx,ecx
- mov edi,edx
- mov dx,gusport104
- gsgetraml0:
- dec edx
- mov al,44h
- mov port103val,al
- out dx,al
- add dl,2
- shld eax,ebx,16
- out dx,al
- sub dl,2
- mov al,43h
- mov port103val,al
- out dx,al
- inc edx
- gsgetraml1:
- mov ax,bx
- out dx,ax
- add dl,3
- insb
- sub dl,3
- inc bx
- loopnz gsgetraml1
- jecxz short gsgetramd
- add ebx,10000h
- jmp gsgetraml0
- gsgetramd:
- pop edi dx ecx ebx eax
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Initialize GUS
- ; In: none
- ; Out:
- ; EAX = 0
- ; EBX = 0 (can be used for determining if memory requuired on cpu, SB returns 1)
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- _gus_init:
- pushad
- mov ax,900h
- int 31h
- push ax
-
- mov dx,_gusport ; set up all port vars
- outb 0bh
- add dx,102h
- mov gusport102,dx
- inc edx
- mov gusport103,dx
- inc edx
- mov gusport104,dx
- add dl,3
- mov gusport107,dx
-
- sub dl,4 ; initialize GUS
- outb 4ch
- add dl,2
- outb 0
- mov ecx,10h
- call gusdelay
- outb 1
- sub dl,2
- mov ecx,10h
- call gusdelay
- gusoutb 41h,0
- gusoutb 45h,0
- gusoutb 49h,0
- outb 0eh
- add dl,2
- mov al,_sfxnumvoices
- dec al
- or al,0c0h
- outb al
- sub dl,3
-
- mov bl,1fh ; set up all voices
- gsinitl0:
- mov al,bl
- and al,7fh
- out dx,al
- inc edx
- gusoutw 9,0
- gusoutb 0,0
- gusoutb 0dh,3
- gusoutb 6,16
- outb 0ch
- add dl,2
- outb 7
- sub dl,3
- mov ecx,1
- call gusdelay
- xor bl,80h
- js gsinitl0
- sub bl,1
- jnc gsinitl0
-
- sub dx,0f3h ; damn, another undocumented port
- outb 5
- sub dl,0fh
- outb 8
- add dl,0bh
- xor al,al
- out dx,al
- add dl,4
- out dx,al
- sub dl,0fh
-
- movzx ebx,_gusirq ; set IRQ channels
- outb 4bh
- add dl,0bh
- mov al,gusirqvaltbl[ebx]
- out dx,al
- sub dl,0bh
- outb 9
- add dx,103h
-
- outb 43h ; how much RAM on the card
- inc edx
- outw 0ffffh
- dec edx
- outb 44h
- add dl,2
- mov cl,3
- gsinitl1:
- outb cl
- add dl,2
- in al,dx
- inc eax
- mov ah,al
- out dx,al
- in al,dx
- sub dl,2
- cmp al,ah
- jne short gsinitl1d
- inc _sfxram
- add cl,4
- test cl,10h
- jz gsinitl1
- gsinitl1d:
- sub dl,2
- shl _sfxram,18
-
- gusoutb 4ch,7 ; enable GUS normal operation
-
- cmp bl,2 ; set and enable GF1 IRQ (BL=IRQ num)
- jne short $+4
- mov bl,9
- cmp bl,7
- seta al
- movzx eax,al
- mov ax,irqm0tbl[eax*2]
- mov irqm0,ax
- mov edx,offset gus_irq
- call _setirqvect
- xor al,al
- call _setirqmask
- mov edi,offset rmgusirqbuf
- call _rmpmirqset
- mov ormgusirqvect,eax
-
- mov whichguscontrol,-1
- call _irq_findcontrol
- jc gusnogus
- mov _irqcontrol[ecx*4],offset _gus_handler
- mov whichguscontrol,ecx
- gusnogus:
- mov ecx,60 ; calculate frequency tables
- mov bl,_sfxnumvoices
- dec bl
- and ebx,1fh
- add bl,1
- mov si,16
- gusfreqcalc:
- mov ax,rawfreq[ecx*2-2]
- call _gus_getfreq
- mov _freqtbl[ecx*2-2],ax
- loop gusfreqcalc
-
- pop ax
- int 31h
- popad
- xor ebx,ebx ; memory flag, 0 = all samples on GUS
- xor eax,eax ; DMA memory flag. 0 = sound blaster DMA not used
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Uninitialize GUS
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _gus_uninit:
- push ax bx edx
- mov ax,900h
- int 31h
- push ax
-
- mov bl,_gusirq ; Kill GUS IRQ handler
- cmp bl,2
- jne short $+4
- mov bl,9
- mov eax,ormgusirqvect
- call _rmpmirqfree
- mov al,1
- call _setirqmask
-
- mov dx,gusport103 ; Shut down GUS
- outb 4ch
- add dl,2
- outb 0
- sub dx,105h
- outb 0bh
-
- mov ecx,whichguscontrol
- or ecx,ecx
- jl gusnovoice
- mov _irqcontrol[ecx*4],offset _ret
- gusnovoice:
-
- pop ax
- int 31h
- pop edx bx ax
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Find a GUS (environment variable)
- ; Out:
- ; EAX,ECX,ESI,EDI - ?
- ; CF=0 - found GUS
- ; CF=1 - no GUS found
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- pspultrastr db 'ULTRASND'
-
- _gus_find:
- pushad
- mov esi,_pspa
- movzx esi,word ptr gs:[esi+2ch]
- shl esi,4
- gsfindl3:
- mov edi,offset pspultrastr
- mov ecx,8
- repe cmps byte ptr gs:[esi],byte ptr es:[edi]
- jne short gsfindf0
- mov edi,10h
- call gsfindr0
- mov _gusport,cx
- call gsfindr0
- call gsfindr0
- mov edi,10
- call gsfindr0
- mov _gusirq,cl
- popad
- clc
- ret
- gsfindf0:
- lea esi,[esi+ecx-8]
- gsfindl0:
- inc esi
- cmp byte ptr gs:[esi-1],0
- jne gsfindl0
- cmp byte ptr gs:[esi],0
- jne gsfindl3
- popad
- stc
- ret
-
- gsfindr0:
- movzx eax,byte ptr gs:[esi]
- inc esi
- sub al,'0'
- jc gsfindr0
- cmp al,9
- ja gsfindr0
- mov ecx,eax
- gsfindr0l0:
- mov al,gs:[esi]
- inc esi
- sub al,'0'
- jc gsfindr0d
- cmp al,9
- ja gsfindr0d
- imul ecx,edi
- add ecx,eax
- jmp gsfindr0l0
- gsfindr0d:
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Shut voice EDI up on GUS
- ; In:
- ; EDI - voice to kill
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- _gus_shutup:
- push edx eax ebx
- mov _vccmnd[edi],0
- mov dx,gusport103
- mov eax,edi
- dec edx ; 3X2
- out dx,al
- inc edx ; 3X3
- gusinb bl,89h
- gusoutb 6,64+48
- gusoutb 7,4
- gusoutb 8,bl
- gusoutb 0dh,40h
- pop ebx eax edx
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Convert actual frequency to GUS frequency number
- ; In:
- ; EAX - frequency
- ; Out:
- ; AX - GUS frequency number
- ; EAX high word - ?
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- _gus_getfreq:
- push edx ebx ebp
- xor ebp,ebp
- mov bp,_sfxmiddlec
- mul ebp
- mov ebp,8664
- div ebp
- xor edx,edx
- shl eax,10
- xor ebx,ebx
- mov bl,_sfxnumvoices
- cmp bl,14
- jae short $+4
- mov bl,14
- mov bx,freqact[ebx*2-14*2]
- div ebx
- pop ebp ebx edx
- ret
-
- freqact dw 44100,41160,38587,36317,34300,32494,30870,29400,28063
- dw 26843,25725,24696,23746,22866,22050,21289,20580,19916,19293
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; SB lowlevel interface. - Everyone knows that the SB is OUTDATED and that
- ; anyone whose anybody has a GUS! These routines are for those losers...
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- public _sb_find
- public _sb_init
- public _sb_uninit
- public _sb_putram
- public _sb_getram
- public _sb_get_dmacount
- public _sb_getfreq
-
- public _sbport
- public _sbirq
- public _sbdmabuffer
- public _sbdmasize
- public _sbmixspeed
- public _sbvoltables
- public _sbsamples
- public _sbvolume
-
- _sbport dw 0
- _sbirq db 0
-
- _sbdmabuffer dd 0 ; DMA buffer
- _sbdmasize dd 0 ; DMA buffer size
- _sbmixspeed dw 0 ; mixing speed, (11000,22000...)
- _sbvoltables dd 0 ; pointer to volume tables
- _sbsamples dd 0 ; sample tables
- _sbvolume db 50 ; overall volume diminishing for samples (256=full) init only
- sbebp dd 0 ; temp ebp 2
- dmaxor dd 0 ; xor value to flip between dma half buffers
- dmachunk dd 0 ; current dma chunk location (front/back)
- dmahalf dd 0 ; _sbdmasize /2
- samend dd 0 ; current sample end location
- saveebp dd 0 ; temp save of ebp
-
- ormsbirqvect dd ? ; old real mode SB IRQ vector
- rmsbirqbuf db 21 dup(?) ; buffer for rm SB IRQ callback code
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Find a SB (environment variable)
- ; Out:
- ; EAX,ECX,ESI,EDI - ?
- ; CF=0 - found GUS
- ; CF=1 - no SB found
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- pspsbstr db 'BLASTER'
-
- _sb_find:
- pushad
- mov esi,_pspa
- movzx esi,word ptr gs:[esi+2ch]
- shl esi,4
- sbfindl3:
- mov edi,offset pspsbstr
- mov ecx,7
- repe cmps byte ptr gs:[esi],byte ptr es:[edi]
- jne short sbfindf0
-
- mov ebx,esi
- mov ecx,10h
- mov al,"A"
- mov ah,"a"
- dec esi
- sbf_loop1:
- inc esi
- cmp byte ptr gs:[esi],ah
- je sbf_it1
- cmp byte ptr gs:[esi],al
- loopne sbf_loop1
- sbf_it1:
- mov edi,10h
- call sbfindr0
- mov _sbport,cx
-
- mov ecx,10h
- mov al,"I"
- mov ah,"i"
- dec ebx
- sbf_loop2:
- inc ebx
- cmp byte ptr gs:[ebx],ah
- je sbf_it2
- cmp byte ptr gs:[ebx],al
- loopne sbf_loop2
- sbf_it2:
- mov esi,ebx
-
- mov edi,10
- call sbfindr0
- mov _sbirq,cl
- popad
- clc
- ret
- sbfindf0:
- lea esi,[esi+ecx-7]
- sbfindl0:
- inc esi
- cmp byte ptr gs:[esi-1],0
- jne sbfindl0
- cmp byte ptr gs:[esi],0
- jne sbfindl3
- popad
- stc
- ret
-
- sbfindr0:
- movzx eax,byte ptr gs:[esi]
- inc esi
- sub al,'0'
- jc sbfindr0
- cmp al,9
- ja sbfindr0
- mov ecx,eax
- sbfindr0l0:
- mov al,gs:[esi]
- inc esi
- sub al,'0'
- jc sbfindr0d
- cmp al,9
- ja sbfindr0d
- imul ecx,edi
- add ecx,eax
- jmp sbfindr0l0
- sbfindr0d:
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Shut voice EDI up on SB
- ; In:
- ; EDI - voice to kill
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- _sb_shutup:
- mov _vccmnd[edi],0
- mov accmnd[edi],0
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Sound Blaster IRQ handler
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- sb_irq:
- push eax
- mov al,20h ; re-enable irq
- out 20h,al
- irqm00 dw ? ; out 0a0h,al | mov eax,eax
- sti
- cld
- push ebx ecx edx esi edi ebp ds
- mov ds, [cs:_seldata]
-
- mov dx,_sbport ; acknowlege sound blaster
- add dx,0eh
- in al,dx
-
- mov eax,dmaxor ; we are now transferring other section...
- xor dmachunk,eax ; flip to other dma chunk
-
- call wipe_dmachunk
- call _sb_handler
-
- pop ds ebp edi esi edx ecx ebx eax
- iretd
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Wipe current dma chunk
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- wipe_dmachunk:
- push edi ecx eax
- mov ecx,dmahalf
- shr ecx,2
- mov edi,dmachunk
- mov eax,80808080h
- rep stosd
- pop eax ecx edi
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Get current DMA location
- ; Out:
- ; ECX = > DMA load location
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_get_dmacount:
- push eax
- xor ecx,ecx
- in al,03h ; get from dma controller
- mov cl,al
- in al,03h
- mov ch,al
- neg ecx
- add ecx,_sbdmasize
- add ecx,_sbdmabuffer
- dec ecx
- pop eax
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Initialize SB
- ; In:
- ; EDX = > free memory for DMA buffer (must be in low memory!)
- ; EAX = > free memory for volume tables, samples (MUST BE HIGHER THAN EDX!!)
- ; EBX = > DMA buffer size (dword aligned)
- ; CX = mixing speed (11000, 22000...)
- ; Out:
- ; CF - 1 error initalizing sound blaster
- ; CF - 0 ok!
- ; EAX = amount EDX was adjusted because of DMA page overlap. eg: add _lomembase,ebx
- ; this includes the original DMA size (0 if GUS)
- ; EBX = 1 (can be used for determining if memory required on cpu, GUS returns 0,eg: imul ebx,200000)
- ;
- ; Notes:
- ; If EAX < or = EDX, samples AND volume tables will follow DMA memory.
- ; Volume tables use 16*256 bytes of memory - make sure you remember this
- ; when allocating memory for samples. 200000 bytes of sample memory req'd
- ; means to allocate 204096 bytes of memory.
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_init:
- pushad
- mov ax,900h
- int 31h
- push ax
-
- mov [esp+28+2],ebx ; mov eax,ebx after final popad
- mov _sbvoltables,eax
- mov _sbdmabuffer,edx
- mov _sbdmasize,ebx
- mov _sbmixspeed,cx
- add edx,_code32a
-
- mov eax,edx ; make sure actual DMA address+size does not
- add eax,ebx ; cross a 64k page boundary
- cmp ax,dx
- ja sb_dmatalk
- dec edx
- xor dx,dx
- add edx,00010000h
- sub edx,_code32a
- mov eax,_sbdmabuffer
- sub eax,edx
- neg eax
- add eax,ebx
- mov [esp+28+2],eax
- mov _sbdmabuffer,edx
- add edx,_code32a
-
- sb_dmatalk:
- mov ecx,ebx
- dec ecx
-
- mov al,05h ; program DMA controller
- out 0ah,al
-
- xor al,al
- out 0ch,al
-
- mov al,dl ; edx = location for DMA
- out 02h,al
- shr edx,8
- mov al,dl
- out 02h,al
- shr edx,8
- mov al,dl
- out 83h,al
-
- mov al,cl ; cx = length
- out 03h,al
- mov al,ch
- out 03h,al
- mov al,01h ; high length
- out 0ah,al
-
- mov al,59h
- out 0bh,al
-
- mov bl,_sbirq ; get protected mode IRQ going
- cmp bl,2
- jne short $+4
- mov bl,9
- cmp bl,7
- seta al
- movzx eax,al
- mov ax,irqm0tbl[eax*2]
- mov irqm00,ax
- mov edx,offset sb_irq
- call _setirqvect
- xor al,al
- call _setirqmask
- mov edi,offset rmsbirqbuf
- call _rmpmirqset
- mov ormsbirqvect,eax
-
- mov edi,_sbdmabuffer ; clear DMA buffer
- mov al,80h
- mov ecx,_sbdmasize
- cld
- rep stosb
-
- sb_resetdsp:
- mov dx,_sbport ; make sure SB is awake and listening
- add dx,06h
- mov al,1
- out dx,al
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- in al,dx
- xor al,al
- out dx,al
- mov cx,100
- sb_waitid:
- mov dx,_sbport
- add dx,0eh
- in al,dx
- or al,al
- js sb_getid
- loop sb_waitid
-
- stc
- jmp sb_error
-
- sb_getid:
- mov dx,_sbport
- add dx,0ah
- in al,dx
- cmp al,0aah
- je sb_sbok
- loop sb_waitid
-
- stc
- jmp sb_error
-
- sb_sbok:
- mov dx,_sbport
- add dx,0ch
- mov ax,1000
- mul ax
- div _sbmixspeed
- neg al
- mov ah,al
- mov dx,_sbport
- add dx,0ch
- sbout 40h ; 40h = set digitized transfer time constant
- sbout ah
-
- sb_startdma:
- mov ebx,_sbdmasize
- shr ebx,1
- dec ebx
- sbout 48h ; 48h = set DSP block transfer size
- sbout bl
- sbout bh
- sbout 1ch ; 1Ch = start auto-initialize mode
- sbout 0d1h ; D1h = turn sound blaster digitized sounds on
-
- mov ebx,_sbdmasize ; set pre-calculated DMA/2 size
- shr ebx,1
- mov dmahalf,ebx
-
- mov eax,_sbdmabuffer ; set xor for chunk flipping
- add ebx,eax
- xor ebx,eax
- mov dmaxor,ebx
- mov dmachunk,eax
- xor dmachunk,ebx ; point active dma chunk to second half (while first half plays)
-
- cmp eax,_sbvoltables
- jb sb_oklocation
-
- add eax,_sbdmasize ; set volume table location
- mov _sbvoltables,eax
- sb_oklocation:
- mov eax,_sbvoltables
- mov esi,eax
-
- add eax,16*256+256 ; set location for virtual ram
- mov _sbsamples,eax
-
- mov ecx,16*256-1 ; generate volume tables
- movzx ebx,_sbvolume ; percentile volume diminishing so sample addition doesn't carry
-
- sb_volloop:
- movzx eax,cl
- sub eax,80h
- movzx edi,ch
- imul edi
- shr eax,4 ; shr eax,4 = full volume
- imul bx
- mov [esi+ecx],ah ; ah rather than shr eax,8
- dec ecx
- jnl sb_volloop
-
- mov ecx,256-1 ; make master volume lookup tables
- sb_mastertables:
- mov ebx,ecx
- mov eax,ecx
- and bl,0fh
- shr al,4
- imul ebx
- imul eax,17
- mov ebx,15*15
- idiv ebx
- cmp al,17
- jne sb_special
- mov al,0fh
- sb_special:
- mov [esi+16*256+ecx],al
- dec ecx
- jnl sb_mastertables
-
- mov ecx,60
- xor ebx,ebx
- sbpitchloop:
- movzx eax,rawfreq[ebx*2]
- call _sb_getfreq
- mov _freqtbl[ebx*2],ax
-
- inc ebx
- loop sbpitchloop
-
- pop ax
- int 31h
- popad
- mov ebx,1
- clc
- ret
-
- sb_error:
- pop ax
- int 31h
- popad
- xor ebx,ebx
- xor eax,eax
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Unintialize SB
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_uninit:
- pushad
- mov ax,900h
- int 31h
- push ax
- mov dx,_sbport
- add dx,0ch
- sbout 0d3h ; D3h = turn sound blaster digitized sounds off
- sbout 0dah ; DAh = exit auto-initialize mode
-
- mov bl,_sbirq ; restore original IRQ
- cmp bl,2
- jne short $+4
- mov bl,9
- mov eax,ormsbirqvect
- call _rmpmirqfree
- mov al,1
- call _setirqmask
- pop ax
- int 31h
- popad
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Shove some crap into SB virtual ram
- ; In:
- ; EBX - addx in SB virtual ram to shove into
- ; ECX - amount of crap to shove
- ; EDX -> actual crap to shove
- ; Notes:
- ; All incomming data will be XOR'ed with _sfxsign !!!
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_putram:
- pushad
- add ebx,_sbsamples
- pr_loop:
- mov al,[edx]
- xor al,_sfxsign
- mov [ebx],al
- inc edx
- inc ebx
- loop pr_loop
- popad
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Rip some crap outta SB virtual ram
- ; In:
- ; EBX - addx in SB virtual ram to rip from
- ; ECX - amount of crap to rip
- ; EDX -> buffer for ripped crap
- ; Notes:
- ; All outgoing data will be XOR'ed with _sfxsign !!!
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_getram:
- pushad
- add ebx,_sbsamples
- gr_loop:
- mov al,[ebx]
- xor al,_sfxsign
- mov [edx],al
- inc edx
- inc ebx
- loop gr_loop
- popad
- ret
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Main loop - Handle sound blaster mixing/voices/looping/bidirectional/volume
- ;
- ; This routine simply emulates a GUS on crappy Sound Blaster.
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_handler:
- movzx ebp,_sfxnumvoices
- dec ebp
-
- _sb_moreloop:
- mov sbebp,ebp
-
- test _vccmnd[ebp],shutup
- jz short sbh_0f9
- mov edi,ebp
- call _sb_shutup
- jmp sbh_next
- sbh_0f9:
-
- test _vccmnd[ebp],vol
- jz sbh_more3
- mov al,_vcvol[ebp]
- mov acvol[ebp],al
- sbh_more3:
-
- test _vccmnd[ebp],freq
- jz sbh_more0
- mov ax,_vcfreq[ebp]
- mov acfreq[ebp*2],ax
- sbh_more0:
-
- test _vccmnd[ebp],play
- jz sbh_more1
-
- mov al,_vccntrl[ebp]
- mov accntrl[ebp],al
- mov eax,_vclbeg[ebp*4]
- add eax,_sbsamples
- mov aclbeg[ebp*4],eax
- mov edx,_vcsbeg[ebp*4]
- add edx,_sbsamples
- mov eax,_vclend[ebp*4]
- add eax,_sbsamples
- mov aclend[ebp*4],eax
- mov acpos[ebp*4],edx
- mov acstep[ebp],0
- mov bh,_vcvol[ebp]
- mov acvol[ebp],bh
- mov ax,_vcfreq[ebp]
- mov acfreq[ebp*2],ax
- mov accmnd[ebp],cont
- mov _vccmnd[ebp],0
- jmp short sbh_mixit
-
- sbh_more1:
- test accmnd[ebp],cont
- jz sbh_next
-
- sbh_mixit:
- mov edx,acpos[ebp*4] ; get actual sample position
- xor ebx,ebx ; clear top word
- mov bl,acvol[ebp] ; get voice volume
- shl bl,4
- or bl,_mix_volume[ebp] ; get channel volume
- xor eax,eax
- mov ax,acfreq[ebp*2] ; get voice frequency scaling
- xor ecx,ecx
- test accntrl[ebp],loop_rev ; set Z flag of looping
- mov cl,ah ; transfer high step temporarily
- mov ah,acstep[ebp] ; get step from last time through
- mov edi,aclend[ebp*4] ; get sample end
- mov ebp,ecx ; set high step for sample increment
- mov samend,edi ; dont have an extra register, must save in memory
- mov ecx,dmahalf ; set loop counter
- mov edi,dmachunk ; find current DMA chunk (front/back half)
- mov esi,_sbvoltables ; point to volume tables
- mov bh,byte ptr [esi+16*256+ebx] ; mix in master volume for channel
- jnz sbh_subloop ; use Z flag from looping
-
- sbh_addloop:
- mov bl,[edx] ; mixing loop, get from sample
- mov bl,[ebx+esi] ; volume cross referance, bh = 0 - 15, bl = byte
- add [edi],bl ; mix into DMA
- inc edi ; inc DMA location
- add ah,al ; increment fractional counter
- adc edx,ebp ; increment integer counter
- cmp samend,edx ; done sample?
- jbe short sbh_firstshot ; yes, check for looping else exit
- dec ecx ; count, dec ecx is faster than loop
- jnz short sbh_addloop
-
- mov ebp,sbebp ; if cpu gets here, sample continues to next DMA chunk
- mov acpos[ebp*4],edx ; save data from this transfer to use in next
- mov acstep[ebp],ah
- jmp sbh_next
-
- sbh_firstshot:
- mov saveebp,ebp ; in case of looping, all registers must remain same
- mov ebp,sbebp
- test accntrl[ebp],loop_on
- jnz sbh_handlelooping
-
- mov ebp,sbebp ; get voice number
- mov accmnd[ebp],0 ; voice done, clear command
- mov _vccmnd[ebp],0 ; clear virtual command
- jmp sbh_next ; do next voice
-
- sbh_subloop:
- mov bl,[edx] ; backwards mixing loop:
- mov bl,[ebx+esi] ; volume cross referance, bh = 0 - 15, bl = byte
- add [edi],bl ; mix into DMA
- inc edi ; inc DMA location
- add ah,al ; increment fractional counter
- sbb edx,ebp ; decrement integer counter this time
- cmp edx,samend ; done sample?
- jbe short sbh_firstshot ; yes, check for looping else exit
- dec ecx ; count, dec ecx is faster than loop
- jnz short sbh_subloop
-
- mov ebp,sbebp ; if cpu gets here, sample continues to next DMA chunk
- mov acpos[ebp*4],edx ; save data from this transfer to use in next
- mov acstep[ebp],ah
- jmp sbh_next
-
- sbh_handlelooping:
- test accntrl[ebp],loop_bi
- jz short sbh_nobidir
- xor accntrl[ebp],loop_rev ; flip direction of loop
- push eax ebx
- mov eax,aclend[ebp*4]
- mov ebx,aclbeg[ebp*4]
- mov aclend[ebp*4],ebx
- mov aclbeg[ebp*4],eax
- mov samend,ebx
- pop ebx eax
- sbh_nobidir:
- mov edx,aclbeg[ebp*4]
- test accntrl[ebp],loop_rev
- jnz sbh_subtest
- mov ebp,saveebp
- dec ecx ; count, dec ecx is faster than loop
- jnz sbh_addloop
-
- sbh_next:
- mov ebp,sbebp
- dec ebp
- jnl _sb_moreloop
-
- ret
-
- sbh_subtest:
- mov ebp,saveebp ; backwards part of bi-directional loop
- dec ecx
- jnz sbh_subloop
- jmp short sbh_next
-
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
- ; Convert actual frequency to SB frequency number
- ; In:
- ; EAX - frequency
- ; Out:
- ; AX - SB frequency scaling number
- ; EAX high word - ?
- ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
-
- _sb_getfreq:
- push ebp ebx
- mov ebp,eax
- mov ax,_sfxmiddlec ; make pitch tables
- shl eax,16 ; step[ebx]="middle c" * rawfreq[ebx] / mixrate / rawfreq[24*2]
- movzx ebx,_sbmixspeed
- cdq
- div ebx
- mul ebp
-
- mov ebp,8664
- div ebp
- shr eax,8
-
- pop ebx ebp
- ret
-
- code32 ends
- end